<template>
  <div class="x-diy-column">
    <x-button :size="buttonSize" :loading="loading" @click="handleVisible">{{ title }}</x-button>
    <n-modal
      v-model:show="visible"
      class="custom-card"
      preset="card"
      :style="{ width: '1000px', height: '800px' }"
      :bordered="false"
      :title="title"
      :mask-closable="false"
    >
      <div style="display: flex; height: 650px; overflow: hidden; border-bottom: 1px solid #e6e8ed">
        <div style="width: 650px; height: 600px">
          <div>
            <n-input v-model:value="keyword" placeholder="搜索指标" clearable @update:value="handleSearch">
              <template #prefix>
                <n-icon :component="SearchOutlined" />
              </template>
            </n-input>
          </div>
          <div style="display: flex; height: 100%">
            <div class="border-r" style="width: 180px; height: 100%">
              <n-scrollbar trigger="none">
                <div>
                  <div class="left-container">
                    <div v-for="(item, index) in list" :key="index" style="margin-bottom: 8px">
                      <div class="t1">{{ item.columnLabel }}</div>
                      <div v-for="(item1, index1) in item.childList" :key="index1" class="t2">{{
                        item1.columnLabel
                      }}</div>
                    </div>
                  </div>
                </div>
              </n-scrollbar>
            </div>
            <n-scrollbar trigger="none">
              <div class="middle-container">
                <n-checkbox-group
                  v-if="visible"
                  v-model:value="checkedList"
                  size="small"
                  @update:value="onChangeChecked"
                >
                  <div v-for="(item1, index1) in secondList" :key="index1">
                    <div class="flex align-center second-list" @click="checkedAllChild(item1)">
                      <div :class="['a-checkbox-box', getSecondCheckedStatus(item1) ? 'a-checkbox-box-active' : '']">
                        <x-icon
                          v-if="getSecondCheckedStatus(item1)"
                          class="icon"
                          name="icon-066"
                          :size="12"
                          color="#ffffff"
                        />
                      </div>
                      {{ item1.columnLabel }}
                    </div>
                    <div class="flex-container">
                      <div class="x-diy-column-list">
                        <div v-for="(item2, index2) in item1.childList" :key="index2" class="item">
                          <n-checkbox
                            :value="item2.columnValue"
                            :disabled="index2 < min || item2.selectStatus === 1"
                            :label="item2.columnLabel"
                          />
                        </div>
                      </div>
                    </div>
                  </div>
                </n-checkbox-group>
              </div>
            </n-scrollbar>
          </div>
        </div>
        <div class="x-diy-column-body" style="flex: 1; background-color: #fafbfc; padding: 18px">
          <n-scrollbar style="max-height: 650px" trigger="none">
            <div class="header">
              <div class="title">
                <span style="flex: 1">已选指标</span>
                <x-button style="float: right" :text="true" type="primary" size="small" @click="handleReset"
                  >清除</x-button
                >
              </div>
              <div v-for="(item, index) in selectList" :key="index" class="spaui-columns-list-item">
                <n-icon style="visibility: hidden"> <MenuOutlined size="14" /></n-icon>
                <span style="flex: 1; margin: 0 8px">{{ item.columnLabel }}</span>
              </div>
            </div>
            <div class="spaui-hr-sect">以上指标将横向固定</div>
            <div class="x-draggable-content">
              <draggable
                v-model="sortCheckedList"
                :group="{ name: 'name', pull: false, put: false }"
                v-bind="dragOptions"
                item-key="id"
              >
                <template #item="{ element }">
                  <div
                    v-if="findLabel(element)?.columnLabel && findLabel(element)?.selectStatus !== 1"
                    :key="element"
                    class="spaui-columns-list-item"
                    style="cursor: pointer"
                  >
                    <n-icon> <MenuOutlined size="14" /></n-icon>
                    <span style="flex: 1; margin: 0 8px">{{ findLabel(element).columnLabel }}</span>
                    <n-icon v-if="isDelete(element)" class="close" @click="handleClose(element)">
                      <CloseOutlined size="14" />
                    </n-icon>
                  </div>
                </template>
              </draggable>
            </div>
          </n-scrollbar>
        </div>
      </div>
      <template #footer>
        <x-button @click="handleCancelDrawer">取消</x-button>
        <x-button type="primary" @click="handleSubmit">保存</x-button>
      </template>
    </n-modal>
  </div>
</template>

<script lang="ts">
  import { CloseOutlined, MenuOutlined, SearchOutlined } from '@vicons/antd'
  import { computed, defineComponent, reactive, toRefs, watch } from 'vue'
  import { NCheckbox, NCheckboxGroup, NIcon, NInput, NModal, NScrollbar } from 'naive-ui'
  import { XButton, XIcon } from '@/components'
  import { store, useStore } from '@/store'
  import { useDictionary } from '@/hooks'
  import draggable from 'vuedraggable'

  export default defineComponent({
    name: 'XDiyColumn',
    components: {
      NCheckboxGroup,
      NCheckbox,
      XButton,
      draggable,
      NInput,
      NIcon,
      NScrollbar,
      MenuOutlined,
      CloseOutlined,
      NModal,
      XIcon
    },
    props: {
      value: {
        type: [Array, Object],
        default: () => []
      },
      // 必填，缓存时需要使用
      name: {
        type: String,
        default: 'name',
        required: true
      },
      title: {
        type: String,
        default: '自定义列'
      },
      min: {
        type: Number,
        default: 4
      },
      // 使用api
      api: {
        type: String,
        default: ''
      },
      // api的params
      apiParams: {
        type: Object,
        default: () => ({
          key: null
        })
      },
      // 使用字典
      isDictionary: {
        type: Boolean,
        default: false
      },
      // 直接使用数据
      data: {
        type: Array,
        default: () => []
      },
      // 按钮大小
      buttonSize: {
        type: String,
        default: 'medium'
      }
    },
    emits: ['update:value', 'save'],
    setup($props, { emit: $emit }) {
      const $dictionary = useDictionary()
      const $store = useStore()
      const $state = reactive({
        ...toRefs($props),
        loading: false,
        visible: false,
        keyword: '',
        // 字典
        dictionary: computed(() => $store.getters.dictionary),
        localName: computed(() => `LOCAL-DIY-COLUMN-${$props.name}`),
        list: [],
        oldList: [],
        checkedList: [],
        oldVal: [],
        // 排序
        sortCheckedList: [],
        dragOptions: computed(() => {
          return {
            animation: 200,
            disabled: false,
            ghostClass: 'ghost'
          }
        }),
        // 第二子集
        secondList: [],
        // 所有子集
        allChildList: [],
        // 必填项
        selectList: [],
        // 默认选中值
        defaultSelect: []
      })
      const isDelete = (val: any) => {
        let arr: never[] = []
        for (let i = 0; i < $props.min; i++) {
          arr.push($state.allChildList[i]?.columnValue)
        }
        return !arr?.includes(val)
      }

      const initList = async () => {
        let localValue = localStorage.getItem($state.localName)
        $state.loading = true
        const { data } = await $store.dispatch($props.api, $props.apiParams)
        // 循环便利二级菜单的是否选中全部
        data.default.forEach((item: any) => {
          item.checkedAll = false
        })
        $state.list = data.default || []
        // 后端存储的默认选中值
        $state.defaultSelect = data.select || []
        // 第二层级
        const secondList = findSecondChild(data.default)
        $state.oldList = JSON.parse(JSON.stringify(secondList)) || []
        $state.secondList = JSON.parse(JSON.stringify(secondList))
        // 所有子集
        const allChildList = findAllChild(data.default)
        $state.allChildList = JSON.parse(JSON.stringify(allChildList))
        // 所有必填值
        const selectList = allChildList.filter((item) => item.selectStatus === 1)
        $state.selectList = JSON.parse(JSON.stringify(selectList))
        // 默认选中值
        const defaultList = allChildList.filter((item) => item.defaultStatus === 1)
        // 接口返回的默认选中值
        if ($state.defaultSelect.length === 0) {
          $state.checkedList = defaultList.map((t) => {
            return t.columnValue
          })
        }
        if (!localValue && $state.defaultSelect?.length === 0) {
          const result = defaultList.map((item) => item.defaultStatus === 1)
          localValue = JSON.stringify(result)
        } else {
          localValue = JSON.stringify($state.defaultSelect)
        }
        $state.loading = false
        // 处理缓存数据
        if (localValue) {
          try {
            const arr = JSON.parse(localValue)
            if (Object.prototype.toString.call(arr) === '[object Array]') {
              arr.forEach((item: string) => {
                if (!$state.checkedList.some((s) => s === item)) {
                  $state.checkedList.push(item)
                }
              })
            }
          } catch (e) {
            console.warn('处理缓存数据错误 ', e)
          }
        }
        $state.oldVal = JSON.parse(JSON.stringify($state.checkedList))
        $state.sortCheckedList = JSON.parse(JSON.stringify($state.checkedList))
        // 初始化完成
        handleSubmit()
      }
      initList()

      // watch
      watch(
        () => $props.name,
        () => {
          initList()
        }
      )
      watch(
        () => $state.visible,
        () => {
          // 关闭抽屉时，重置数据
          $state.checkedList = $state.oldVal
          $state.sortCheckedList = $state.oldVal
        }
      )

      const handleVisible = () => {
        $state.visible = true
      }

      const handleCancelDrawer = () => {
        $state.visible = false
      }

      const handleReset = () => {
        $state.checkedList = $state.checkedList.filter((item, index) => {
          return index < $props.min
        })
        const resetList = $state.checkedList || []
        $state.selectList.forEach((item: any) => {
          if (item?.selectStatus === 1) {
            resetList.push(item.columnValue)
          }
        })
        $state.sortCheckedList = $state.checkedList
      }

      const onChangeChecked = () => {
        $state.sortCheckedList = JSON.parse(JSON.stringify($state.checkedList))
      }

      const findLabel = (val: any) => {
        const list = findAllChild($state.list)
        for (let i = 0; i < list.length; i++) {
          if (list[i].columnValue === val) {
            return list[i]
          }
        }
      }

      const findAllChild = (list: any) => {
        let result: { columnValue: any; columnLabel: any }[] = []
        list?.forEach((item: any) => {
          item.childList?.forEach((item1: any) => {
            item1.childList?.forEach((item2: any) => {
              result.push(item2)
            })
          })
        })
        return result
      }
      const findSecondChild = (list: any) => {
        let result: { columnValue: any; columnLabel: any }[] = []
        list?.forEach((item: any) => {
          item.childList?.forEach((item1: any) => {
            result.push(item1)
          })
        })
        return result
      }

      // 全选/取消全选当前下的子集
      const checkedAllChild = (list: any) => {
        const ids =
          list.childList.map((item: any) => {
            // if (item.selectStatus !== 1) {
            return item.columnValue
            // }
          }) || []
        const result = $state.checkedList.filter((item) => !ids.includes(item))
        let isSubset = ids.every((item: any) => $state.checkedList.includes(item))
        if (isSubset) {
          $state.checkedList = result
        } else {
          let mergedArray = $state.checkedList.concat(ids)
          let uniqueArray = [...new Set(mergedArray)]
          $state.checkedList = uniqueArray
        }
        const disabledIds: any[] | ConcatArray<never> = []
        list.childList.forEach((item: any) => {
          if (item.selectStatus === 1) {
            disabledIds.push(item.columnValue)
          }
        })
        let mergedArray = $state.checkedList.concat(disabledIds)
        let uniqueArray = [...new Set(mergedArray)]
        $state.checkedList = uniqueArray

        $state.sortCheckedList = $state.checkedList
      }

      const getSecondCheckedStatus = (item: any) => {
        const ids =
          item.childList.map((item: any) => {
            return item.columnValue
          }) || []
        return ids.every((item: any) => $state.checkedList.includes(item))
      }

      const handleClose = (val: any) => {
        $state.checkedList = $state.checkedList.filter((item) => item !== val)
        $state.sortCheckedList = $state.sortCheckedList.filter((item) => item !== val)
      }

      const handleSubmit = () => {
        // 缓存至本地
        // localStorage.setItem($state.localName, JSON.stringify($state.checkedList))
        localStorage.setItem($state.localName, JSON.stringify($state.sortCheckedList))
        // console.log(11, $state.checkedList)
        $state.oldVal = $state.sortCheckedList
        store.dispatch('dictionary/columnSave', {
          key: $state.apiParams.key,
          list: $state.sortCheckedList
        })
        // 排序后的值
        $emit('update:value', $state.sortCheckedList)
        $emit('save', true)
        // $emit('update:value', $state.checkedList)
        $state.visible = false
      }

      // 搜索
      const handleSearch = () => {
        if (!$state.keyword) {
          $state.secondList = $state.oldList
        } else {
          // 查找所有元素
          const filterList = $state.allChildList.filter((item: any) => item.columnLabel.includes($state.keyword))
          const idList = filterList.map((t) => t.parentId)
          const oldList = JSON.parse(JSON.stringify($state.oldList))
          const t = oldList.filter(function (item: any) {
            return idList.includes(item.id)
          })
          t.forEach((item: any) => {
            const children: never[] = []
            item.childList.forEach((item1: any) => {
              filterList.forEach((item2) => {
                if (item2.id === item1.id) {
                  children.push(item2)
                }
              })
              item.childList = children
            })
          })
          $state.secondList = t
        }
      }

      return {
        ...toRefs($state),
        handleVisible,
        handleSubmit,
        handleCancelDrawer,
        isDelete,
        findLabel,
        handleReset,
        onChangeChecked,
        handleClose,
        handleSearch,
        SearchOutlined,
        checkedAllChild,
        getSecondCheckedStatus
      }
    }
  })
</script>

<style lang="scss" scoped>
  @import '@/assets/styles/var.scss';

  .x-diy-column-body {
    .header {
      background: #fff;
      .title {
        display: flex;
        padding: 10px;
        align-items: center;
      }
    }
  }
  .x-diy-column-list {
    display: flex;
    flex-wrap: wrap;
    width: 100%;
    padding: 12px;
    .item {
      width: 50%;
      padding: 5px;
    }
  }
  .spaui-hr-sect {
    display: flex;
    padding: 5px 0;
    flex-basis: 100%;
    align-items: center;
    color: #939599;
    font-size: 12px;
  }
  .spaui-hr-sect::after,
  .spaui-hr-sect::before {
    content: '';
    flex-grow: 1;
    background: #edeff2;
    height: 1px;
    font-size: 0;
    line-height: 0;
  }
  .spaui-hr-sect::before {
    margin: 0 16px 0 0;
  }
  .spaui-hr-sect::after {
    margin: 0 0 0 16px;
  }
  .spaui-columns-list-item {
    display: flex;
    align-items: center;
    padding: 10px 15px;
    background: #fff;
    border-top: 1px solid #edeff2;
    .close {
      visibility: hidden;
    }
  }
  .spaui-columns-list-item:hover {
    .close {
      visibility: visible;
    }
  }
  .spaui-columns-list-item:first-child {
    border-top: none;
    border-top-left-radius: 4px;
    border-top-right-radius: 4px;
  }
  .border-r {
    border: 1px solid #e6e8ed;
    border-left-width: 0;
    border-top-width: 0;
    border-bottom-width: 0;
  }
  .left-container {
    padding-top: 10px;
    .t1 {
      font-size: 16px;
      font-weight: 600;
      margin-bottom: 8px;
    }
    .t2 {
      padding-left: 12px;
    }
  }
  .middle-container {
    padding: 10px;
    .second-list {
      display: flex;
      padding-left: 12px;
      height: 36px;
      background: #f7f9fc;
      border: 1px solid #f2f4f7;
      border-radius: 4px;
      cursor: pointer;
    }
    .flex-container {
      display: flex;
      width: 100%;
      .wd50 {
        width: 50%;
      }
    }
  }
  .a-checkbox-box {
    height: 14px;
    width: 14px;
    display: flex;
    align-items: center;
    box-sizing: border-box;
    border: 1px solid rgb(224, 224, 230);
    margin-right: 8px;
    border-radius: 2px;
  }
  .a-checkbox-box-active {
    background: $primaryColor;
    border: 1px solid #536fff;
  }
</style>
